perm filename ALKERN.POX[HAL,HE]2 blob sn#190992 filedate 1975-12-06 generic text, type C, neo UTF8
COMMENT āŠ—   VALID 00004 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	\!head2(THE KERNEL)
C00006 00003	\!head3(The Process Descriptor Block)
C00010 00004	\!head3(System Calls)
C00019 ENDMK
CāŠ—;
\!head2(THE KERNEL);

\F0\JThe kernel resides in low core (0 to 13777) of the PDP11.
When it is started at location 1000, it finds the
user's starting address at 13776 and a pointer to his processor
descriptor block at 13777.  When the AL system is the "user", it is the
interpreter initialization code that is pointed to by these words.
Control is passed to the user (in cpu user mode).\.

\JProcesses communicate with the kernel by means of the EMT (emulator
trap) instruction.  Mechanisms are provided to control multiple
processes, including time-slice scheduling, priority
assignment, and an event mechanism with signal and wait
primitives.  All system calls pop their arguments off the user stack
and push their return values if they have any.  They mostly return
with the C condition code bit zero.  An error condition causes a
return with C=1; in that case, the arguments have been popped and no
return values pushed.\.

\JThe basic time quantum in the kernel is currently 2 milliseconds,
although it will eventually be run at 1 millisecond.
At the start of each
quantum, all processes which are scheduled for execution are readied,
and those with higher priority have precedence.  Any unused time
is soaked up by the null job.\.

\,
\!head3(The Process Descriptor Block);

\JEach user process is accessed by means of a user process descriptor
block (PDB).
The PDB contains all of the state information for a user process. 
The things a new process must have set up are UFPUSE and UDPUSE, to tell whether
the process uses floating point; UGRSAV, UFPSAV, and USKSAV if it is intended
to give the process some initial information in its general
registers, floating registers, or stack (if you set USKSAV to 1, you
must also put a reasonable value into USKP); and UPC for servo
processes that are scheduled with a SCHED7 operation.  UPDLEN should
be set to the number of bytes (!) in the process descriptor block. 
The Kernel sets up the rest. 
The actual fields of the PDB are described below:\.

\F3\;
UST0		Status codes, containing the following:

	UFPUSE = 100000		He uses floating point.
	UDPUSE = 040000		He uses double precision.
	UFPSAV = 020000		His floating point stuff is in the PDB.
	USKSAV = 010000		Ditto his stack pointer,
	UGRSAV = 004000		general registers,
	UPCSAV = 002000		PC and PSW.
		    377		Low byte contains 2*(nominal priority).

UPDLEN 		Length of the PDB (bytes).
USKMIN 		Min and max values for SP.
USKMAX 
UINTL		Link to job this one pre-empted.
UCALL		Kernel SP when this job is interrupted.
PDBSP = USKP	Stack pointer,
PDBPC = UPC	program counter,
UPSW		and condition codes.

\jThe next six words are where the Kernel stores your
general registers when your process is inactive.  For jobs
created with a SCHED7, UGRSAV is forced to 1 in order to
load the data pointers into your registers.\.

PDBR0 = UGR0	General registers R0-R2
PDBR1	 
PDBR2	 
PDBR3 = UADLST 	R3 - AD channel list pointer
PDBR4 = UADDAT 	R4 - AD data pointer
PDBR5		R5

\jThe next part is for jobs that use floating point.
You can leave it out of the PDB for fixed-point-only jobs.\.

UFEC		Floating Exception Code and address are
UFEA		stored here when a floating-point trap happens.
		You can test for traps by checking the FEC for non-zero 
		(you have to clear it yourself).

UFPS		Floating Point Status
UAC0		12 words for the AC's in single precision,
		24 if UDPUSE is on.

\jThe rest of the block is your stack.  Any time you become inactive,
the kernel checks your stack pointer and gives a horrendous error
if it is out of bounds.\.

\,
\!head3(System Calls);

A description of each of the system calls follows.

system call	DISMIS (no arguments)

\JKills the process that uses it.  It saves the PC, PSW, and SP but nothing else.
If the process is restarted (as in the level 7 SCHED7-DISMIS sequence) it will
resume after the DISMIS with the stack in the right state but all registers
clobbered.  R3 through R5 will be reloaded with what they had at the first
startup.\.


system call	FORK PDB,LOC,PRI

\JStarts up a new process immediately.  PDB points at
a process descriptor, LOC is the starting address, and PRI is the
priority of the new process.  If PRI is higher than that of the
calling process the new one will run immediately and pre-empt the
caller.  FORKing with PRI=7 will work but is not a good idea since
if you do it too late in a clock period the clock might miss a tick.\.


system call	SCHEDU PDB,LOC,PRI,TIME

\JWorks just like FORK except that instead
of starting the target process immediately it puts the process on
the clock queue to start up TIME milliseconds from now.  This will
also work if PRI=7, but if anotheplevel 7 process is already scheduled
for that slot the new one will be put into the queue in the first
available slot after the one you requested.\.


system call	SCHED7 ARRAY,TIME

\JIs a special variation on SCHEDU to allow scheduling
a whole bunch of priority 7 jobs at one whack.  ARRAY points at an array that
consists of a pointer to a PDB, a return value, another
PDB pointer, another return value, etc., ending with a zero where the
next PDB pointer should be.  TIME is the number of milliseconds from
now that the first process should start up.  SCHED7 puts the processes
into consecutive time slots if it can.  If a slot is already filled,
it uses the next available one.  In any case, it returns for each
process the  number of milliseconds from now that it wound
up being scheduled.\.

\JLevel 7 is the highest priority.  This level is only used for
critical operations such as reading the analog-to-digital converter
(ADC) and servoing device joints.  Only one level 7 process can be
scheduled for any given time slot.  When the Kernel starts a level 7
job running, it interprets the contents of user registers R3 and R4 in
the PDB (Process Descriptor Block) 
as pointers to two data arrays.  R3 points at a list of ADC
channel numbers (one per word) terminated by a negative number.  The
startup routine reads all the channels specified in the array and
puts the results into the corresponding locations in the array to which
R4 points.  When the user process gets control, R3 and R4 point at
the first words of the two arrays and all of the channels have been
read.  The recommended way for a level 7 job to reschedule itself is
to do a SCHED7 to its own PDB, take note of the returned actual time
interval, and then DISMIS.  This procedure minimizes
overhead by not saving and restoring the registers.  NOTE: Since
level 7 can not be interrupted (even by floating-point traps), no
PDB space is allocated for any of the floating-point registers.\.


system call	SLEEP TIME

\JPuts the requesting process to sleep for TIME milliseconds.
If TIME=0, this merely reschedules the process for the present time slot.
If its priority is 7 and the time requested is already reserved, it will
be scheduled in the first later available slot.\.


system call	EVMAK (no args)

\JCreates an event with its associated counter and
empty queue of waiting jobs.  It returns a unique identifier which
can be used later to refer to the event.  Events come in two flavors:
the kind created with this operation, and "permanent" ones that
reflect hardware conditions.  Permanent events are identified by
small integers.  There are currently no permanent events.\.


system call	EVKIL <event id>

\JDestroys the event if it was not a permanent event,
waking up any processes that are waiting and giving them the C=1
return.  If the id doesn't point at an event, or points to a permanent
event, EVKIL does nothing and gives the error return.\.


system call	EVSIG <event id>

\JSignals the event.  If any processes are waiting, the
first one will wake up.  EVSIG of a permanent event does nothing but
give the error return.\.


system call	EVWAIT <event id>

\JTests the event (of either type) and makes the normal
return if it has happened,
thereby decreasing the count on that event.
  If it hasn't happened, the requesting process goes
to sleep waiting for it and gets the normal return when it does happen.
If it is not an event, or it becomes EVKILled while the process is waiting,
the error return is taken.  The queue of jobs waiting on an event is
ordered by their nominal priorities, first come first served within
priority levels.\.


system call	EVTST <event id>

\JTests the event and returns as with EVWAIT if it has happened.
If it hasn't, or if it's a non-event, the error return is taken without
waiting.\.


system call	SETPRI PRI

\JSets the priority of the calling process 
to PRI or the priority it was originally
run at, whichever is higher, and returns the old priority on the stack.
If attempt is made to set the priority below the original, the failure
return (C=1) is taken.\.


system call	GETTIM (no args)

\JReturns the time in milliseconds since the Kernel was last
initialized on the user stack.
The result is a two-word integer in the right format for
a LDCLF or LDCLD instruction.\.